// Copyright 2021 by 马万里. All rights reserved.
// 开发团队 ：   鸡中之霸
// 开发人员 ：   马万里
// 开发时间 ：   2021/3/3 20:47
// 文件名称 ：   aes.go
// 工程名称 ：   seckill
// 开发工具 ：   GoLand
//

package encrypt

import (
	"bytes"
	"crypto/aes"
	"crypto/cipher"
	"encoding/base64"
	"errors"
	"fmt"
)

var PwdKey = []byte("seckilljohnsonhh")

// PKCS7填充模式
func PKCS7Padding(ciphertext []byte, blockSize int) []byte {
	padding := blockSize - len(ciphertext)%blockSize
	padText := bytes.Repeat([]byte{byte(padding)}, padding)
	return append(ciphertext, padText...)
}

// 去除填充
func PKCS7UnPadding(origData []byte) ([]byte, error) {
	length := len(origData)
	if length == 0 {
		return nil, errors.New("加密字符串错误!")
	}
	// 获取填充的长度
	unpadding := int(origData[length-1])
	// 截取切片,删除填充字节,并返回明文
	return origData[:length-unpadding], nil
}

// 实现加密
func AESEncrypt(origData []byte, key []byte) ([]byte, error) {
	block, err := aes.NewCipher(key)
	if err != nil {
		return nil, err
	}
	// 获取blocksize
	blockSize := block.BlockSize()
	// 对元数据进行填充
	origData = PKCS7Padding(origData, blockSize)
	// 采用AES的CBC加密模式
	cbcEncrypter := cipher.NewCBCEncrypter(block, key[:blockSize])
	crypted := make([]byte, len(origData))
	// 执行加密
	cbcEncrypter.CryptBlocks(crypted, origData)
	return crypted, nil
}

// 解密
func AESDecrypt(cripted []byte, key []byte) ([]byte, error) {
	// 创建加密算法实例
	block, err := aes.NewCipher(key)
	if err != nil {
		return nil, err
	}
	// 获取blocksize
	blockSize := block.BlockSize()
	if err != nil {
		return nil, err
	}
	// 解密
	cbcDecrypter := cipher.NewCBCDecrypter(block, key[:blockSize])
	origData := make([]byte, len(cripted))
	cbcDecrypter.CryptBlocks(origData, cripted)
	// 对元数据进行去填充
	origData, err = PKCS7UnPadding(origData)
	return origData, nil
}

// base64编码
func EnPwdCode(pwd []byte) (string, error) {
	result, err := AESEncrypt(pwd, PwdKey)
	if err != nil {
		return "", err
	}
	return base64.StdEncoding.EncodeToString(result), nil
}

func DePwdCode(pwd string) ([]byte, error) {
	pwdByte, err := base64.StdEncoding.DecodeString(pwd)
	if err != nil {
		fmt.Println(err)
		return nil, err
	}
	return AESDecrypt(pwdByte, PwdKey)
}
